/* 
    参考：Promise A+ 规范编写的Promise实现 https://promisesaplus.com/
    1. 创建promise的时候回传递一个执行器，并且立即执行
    2. 状态初始化处理 执行器有两个参数函数分别resolve改变为成功状态；reject
    3. resolve 和 reject 判断状态如果不是出于pending状态则不执行
    4. 保存resolve的value值以及保存reject的reason值
    5. then 方法的基本实现 首先实现执行器无异步的情况 A promise must provide a then method to access its current or eventual value or reason.
    6. 处理执行器异步执行resolve或reject，时then方法的处理
    7. 处理then方法多次调用的情况 then may be called multiple times on the same promise.
    8. then must return a promise then必须返回一个Promise对象 如果回调函数返回普通值则下一次then返回当前值
    如果返回的是promise对象则返回promise执行器的值
    9. then 返回一个相同的promise对象的情况处理
    10. then 参数可选处理
    11. 异常情况处理 执行器异常 以及 then方法异常
    12. catch 方法
    13. finally 方法实现
    14. 静态方法的实现
*/
const STATUS = {
    PENDING: 'pending',//等待
    FULFILLED: 'fulfilled',//成功
    REJECTED: 'rejected'//失败
}
class MyPromise {
    constructor(executer) {
        try {
            executer(this.resolve, this.reject);
        } catch (e) {
            this.reject(e);
        }
    }
    status = STATUS.PENDING;
    value = undefined;
    reason = undefined;
    onFulfilled = [];
    onRejected = [];
    //通过箭头函数避免this指向的问题 使得this指向MyPromise对象
    resolve = (value) => {
        //判断状态是否为pending
        if (this.status !== STATUS.PENDING) {
            return;
        }
        //设置状态为fulfilled
        this.status = STATUS.FULFILLED;
        //保存value值
        this.value = value;
        //如果存在回调成功状态的函数则执行
        while (this.onFulfilled.length) {
            this.onFulfilled.shift()();
        }
    }
    reject = (reason) => {
        //判断状态是否为pending
        if (this.status !== STATUS.PENDING) {
            return;
        }
        //设置状态为rejected
        this.status = STATUS.REJECTED;
        //保存reason
        this.reason = reason;
        //如果存在回调失败状态的函数则执行
        while (this.onRejected.length) {
            this.onRejected.shift()();
        }
    }
    then(onFulfilled, onRejected) {
        onFulfilled = onFulfilled ? onFulfilled : value => value;
        onRejected = onRejected ? onRejected : err => { throw err };
        let p = new MyPromise((resolve, reject) => {
            //判断状态
            if (this.status === STATUS.FULFILLED) {
                //这里为什么要加上settimeout呢？这样就可以拿到p对象
                setTimeout(() => {
                    try {
                        let result = onFulfilled(this.value);
                        this._resolveResult(p, result, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            } else if (this.status === STATUS.REJECTED) {
                setTimeout(() => {
                    try {
                        let result = onRejected(this.reason);
                        this._resolveResult(p, result, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            } else {
                //如果状态还是pending就说明 执行器中的代码进行了异步处理 那么就需要记录下两个回调函数
                //等执行器执行完毕后调用相对应的记录的回调函数
                this.onFulfilled.push(() => {
                    setTimeout(() => {
                        try {
                            let result = onFulfilled(this.value);
                            this._resolveResult(p, result, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
                this.onRejected.push(() => {
                    setTimeout(() => {
                        try {
                            let result = onRejected(this.reason);
                            this._resolveResult(p, result, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
            }
        });
        return p;
    }
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }
    finally(callback) {
        return this.then(res => {
            return MyPromise.resolve(callback()).then(() => res);
        }, err => {
            return MyPromise.resolve(callback()).then(() => { throw err });
        });
    }
    static all(array) {
        let result = []
        let index = 0;
        //注意需要考虑 传入的数组中promise执行器异步的情况 可以通过一个计数器进行判断
        return new MyPromise((resolve, reject) => {
            function addData(key,value) {
                result[key]=value;
                index++;
                if (index === array.length) {
                    console.log(index);
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let s = array[i];
                //判断s是否为Promise对象
                if (s instanceof MyPromise) {
                    s.then(res => {
                        console.log(res);
                        addData(i,res);
                    }).catch(err => {
                        reject(err);
                    });
                } else {
                    addData(i,s);
                }
            }
        });
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value;
        }
        return new MyPromise((resolve, reject) => {
            resolve(value);
        });
    }
    static reject(error) {
        return new MyPromise((resolve, reject) => {
            reject(error);
        })
    }
    /**
     * 判断哪个先执行完毕
     * @param {*} array 
     */
    static race(array){
        return new MyPromise((resolve,reject)=>{
            for(let i=0;i<array.length;i++){
                let p = array[i];
                p.then(res=>{
                    resolve(res);
                    break;
                }).catch(err=>{
                    reject(err);
                    break;
                })
            }
        });
    }
    _resolveResult(p, result, resolve, reject) {
        // console.log(result);
        if (p === result) {//相同的回调 跑出错误处理
            reject(new Error('result === p'));
            throw Error('result === p');
        }
        // console.log(result);
        if (result instanceof MyPromise) {
            console.log('result is Promise');
            //将promise对象的值，放到下一个then回调的中
            result.then(resolve, reject);
        } else {
            //普通值直接调用resolve 下一次调用then会得到result
            console.log('resolve');
            resolve(result)
        }
    }
}

module.exports = MyPromise;